<!--
通用表格对象
包含表格工具栏、分页插件，并提供了多个插槽来解决各种定制需求
最后修改：20220409
作者：ljy
一、用法
（一）基本用法
1.1 引入组件的方式
import Table from '@/components/base/table/Table.vue';
1.2 使用方式
<Table
      :table="table"
      :tableColumns="tableColumns"
      :loadTableList="loadTableList"
      :changePageSize="changePageSize"
      :changePage="changePage"
    >
1.3 参数说明：
1.3.1 table、loadTableList、changePageSize和changePage的详细说明参照文件'@/api/uem/useTableList.ts'，为表格封装的必备元素
1.3.2 tableColumns为表格的列字段集合，用于实现表格的动态显示。
例如：各种类型的解释详见@/types/interface/base_interface的TableColumn接口
const tableColumns = ref<TableColumn[]>([
  {
    label: '角色名称',
    prop: 'nameZh',
    fixed: true,
  },
  {
    label: '角色标识',
    prop: 'name',
    width: 150,
  },
  {
    label: '默认角色',
    prop: 'defaultRole',
    width: 100,
    type: 'custom',
  },
  {
    label: '启用状态',
    prop: 'enabled',
    width: 100,
    type: 'custom',
  },
  {
    label: '创建时间',
    prop: 'createTime',
  },
]);
1.3.2.1 type参数说明：
（1）普通列字段
如果type属性为空，则默认直接显示该字段的值。
字段示例：
 {
    label: '创建时间',
    prop: 'createTime',
  },
（2）在字典中取出键对应的值
要求type属性为dict；并且dict属性要有值传入，且类型为Option[]。
例如字典{1:'男',2,'女'}，账户性别为1则显示为男。
字段示例：
  {
    label: '默认角色',
    prop: 'defaultRole',
    width: 100,
    type: 'dict',
    dict: yesOrNoDict,
  },
（二)表格插槽
说明表格工具栏、表格只包含了基本的功能，实际开发中通常需要满足各种需求，此时可以插槽进行定制开发
1.表格插槽
1.1 定制列插槽
说明：一般用在业务展示要求比较高的指定表格列
1.1.1 例：默认角色
<template #defaultRole="scope">
  <el-tag :type="`${scope.row.defaultRole==true ? 'success' : 'info'}`">{{dictToMap(yesOrNoDict).get(scope.row.defaultRole)}}</el-tag>
</template>
（1）满足条件
首先需要将该字段设置为type: 'custom',如下
[
  ……
  {
    label: '默认角色',
    prop: 'defaultRole',
    width: 100,
    type: 'custom',
  },
  ……
]
（2）<template #defaultRole="scope">的说明
#defaultRole对应列属性defaultRole
scope的值包含两个，分别是row和item属性。其中row属性与element-table中的scope.row属性一致；scope.item属性为字段列的信息。
1.2 定制操作列插槽（一般在右侧）
说明：一般用对表格单行有特殊操作要求的时候
1.1.1 例如：
<template #table_right_operator>
  <el-table-column
    fixed="right"
    label="操作"
    align="center"
    width="330">
    <template #default="scope">
      <el-button  type="primary"  size="small" icon="Edit" plain @click="print(scope.row);">编辑</el-button>
      <el-button  type="primary"  size="small" icon="User" plain>分配权限</el-button>
    </template>
  </el-table-column>
</template>
（1）满足条件
无
（2）<template #defaultRole="scope">的说明
#defaultRole对应列属性defaultRole
scope的值主要包括row属性，其中row属性与element-table中的scope.row属性一致。

2.表格工具栏插槽
2.1 表格左侧工具栏的右侧插槽
说明：在工具栏左侧需要增加操作组件时使用
2.1.1 例：在左侧工具栏右侧插入一个图标
<template #toorbar_left_right>
  <el-button icon="Plus" type="primary" style="margin-left: 0;">分配角色</el-button>
</template>

-->
<template>
  <div>
    <!--表格工具栏-->
    <TableToolbar
      ref="tableOperationRef"
      v-show="showToolBar"
      :showLeftToolBar="showLeftToolBar"
      :showRightToolBar="showRightToolBar"
      :showEditButtonInToolBar="showEditButtonInToolBar && showEditButton"
      :showAddNewButton="showAddNewButton"
      :AddNewButtonText="AddNewButtonText"
      :query="query"
      :isTreeTable="isTreeTable"
      :tableColumns="tableColumns"
      :multipleSelection="multipleSelection"
      :loadTableList="loadTableList"
      :showDeleteMultipleSelectionButton="
        showDeleteMultipleSelectionButton && showDeleteButton && typeof baseUrl === 'string' && baseUrl.length > 0 && showTableCheckbox
      "
      :importUrl="importUrl"
      :importButtonText="importButtonText"
      :importExcelSuccessAndCloseDialog="importExcelSuccessAndCloseDialog"
      :downloadTemplateUrl="downloadTemplateUrl"
      :templateFileName="templateFileName"
      :downloadUrl="downloadUrl"
      :dataFileName="dataFileName"
      @tableLadding="changeTableLoading"
      @changeColumnSelect="getColumnsSelected"
      @deleteMultipleSelection="deleteMultipleSelection"
      @addRow="addRow"
      @editRow="editRow"
      @expandAll="expandAll"
      @shrinkAll="shrinkAll"
    >
      <!--把表格左侧工具栏的右侧插槽继续网上暴露-->
      <template #toorbar_left_right>
        <slot name="toorbar_left_right"></slot>
      </template>
    </TableToolbar>
    <!--表格对象-->
    <el-table
      ref="tableRef"
      v-if="refreshTable"
      :data="table.data"
      :height="tableHeight"
      :row-key="rowId"
      table-layout="fixed"
      v-loading="tableLoading"
      @selection-change="handleSelectionChange"
      @row-click="rowClick"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      highlight-current-row
      :default-expand-all="isExpandAll"
      stripe
      border
      max-height="600px"
    >
      <el-table-column v-if="showTableCheckbox" type="selection" width="40" align="center" />
      <el-table-column v-if="showTableIndex" align="center" type="index" fixed />
      <template v-for="(item, index) in tableColumnsVisible" :key="index + 5">
        <el-table-column
          :label="item.label"
          :prop="item.prop"
          :width="item.width"
          :fixed="item.fixed"
          show-overflow-tooltip
          :align="item.align ? item.align : 'center'"
        >
          <template #default="scope">
            <!--自定义表格列插槽，在父组件自行进行创建-->
            <span v-if="item.type === 'custom'">
              <slot :name="'table_column_' + item.prop" v-bind:item="item" v-bind:row="scope.row"> </slot>
            </span>
            <span v-else-if="item.type === 'dict' && item.dict">
              <!--如果要按照标签展示，例如某值用绿色，某值用红色-->
              <template v-if="item.config && item.config.dictTag">
                <!--遍历dictTag中存在的属性名和属性-->
                <template v-for="(valueArray, key) in item.config.dictTag" :key="key">
                  <!--遍历dictTag中每个属性对应的数组-->
                  <template v-for="(value, index2) in valueArray" :key="index2">
                    <el-tag v-if="value === scope.row[item.prop]" :type="key">{{ dictToMap(item.dict).get(scope.row[item.prop]) }}</el-tag>
                  </template>
                </template>
                <!-- <template v-if="item.config.dictTag.primary">
                  <template v-for="(value, index2) in item.config.dictTag.primary">
                    <el-tag :key="index2" v-if="value === scope.row[item.prop]" type="primary">{{
                      dictToMap(item.dict).get(scope.row[item.prop])
                    }}</el-tag>
                  </template>
                </template> -->
                <!-- 如果没有匹配任何属性,则默认显示下面的文字内容。
                 说明：因为scope.row[item.prop]报错any不允许赋值给never（实际可以运行），因此加上scope.row[item.prop] as never
                 -->
                <span v-if="Object.values(item.config.dictTag).every((arr) => !arr.includes(scope.row[item.prop] as never))">
                  {{ item.dict ? dictToMap(item.dict).get(scope.row[item.prop]) : '' }}
                </span>
              </template>
              <template v-else>
                <!--默认效果，因为字典的值可能有多少类型，这里统一转换为字符串判定-->
                {{ item.dict ? dictToMap(item.dict).get(scope.row[item.prop]) : '' }}
              </template>
            </span>
            <span v-else-if="item.type === 'icon'">
              <el-icon v-if="scope.row[item.prop]">
                <component :is="scope.row[item.prop]"></component>
              </el-icon>
            </span>
            <!--用div来限制el-image的高度，避免el-image会有部分高度超出——原因未明-->
            <div v-else-if="item.type === 'image'" style="display: block; height: 30px">
              <!-- 20240813：虽然图片插件PictureComponent自带同名图片刷新，但是在表格刷新时不生效，因此这里也要手动加上随机数让浏览器刷新 -->
              <PictureComponent
                :picUrl="scope.row[item.prop] != null && scope.row[item.prop] != '' ? scope.row[item.prop] + '?' + Math.random() : ''"
              />
            </div>
            <!--如果是swich类型-->
            <el-switch
              v-else-if="item.type === 'switch'"
              v-model="scope.row[item.prop]"
              inline-prompt
              active-text="是"
              inactive-text="否"
              :style="`width:${item.width ? item.width : ''}`"
              @change="emit('saveRow', scope.row)"
            />
            <!--例如：router.push({path: '/backstage/wms/warehousearea',query: {warehouseId}});-->
            <!-- <el-link v-else-if="item.type === 'link'" @click="router.push(item.routerDate)">{{ scope.row[item.prop] }}</el-link> -->
            <!-- 文本编辑模式。 -->
            <template v-else>
              <!-- 如果编辑属性名存在则说明该文本处于编辑中；在编辑结束后重新去取消编辑 
               注意：如果按ESC就取消编辑，这里因为时间关系直接偷懒刷新表格了，后续再手动去回复原始值-->
              <div v-if="scope.row._editColumnName && scope.row._editColumnName == item.prop">
                <el-input
                  v-model="scope.row[item.prop]"
                  @blur="saveRow(scope.row)"
                  @keyup.enter="saveRow(scope.row)"
                  @keyup.esc="loadTableList"
                  autofocus
                />
              </div>
              <!-- 先通过双击文本获取要编辑的属性名 -->
              <span v-else @dblclick="allowEditTableCell ? (scope.row._editColumnName = item.prop) : null">
                {{ scope.row[item.prop] }}
              </span>
            </template>
          </template>
        </el-table-column>
      </template>
      <!--自定义插槽，操作列-->
      <el-table-column v-if="showOperatorColumn" fixed="right" label="操作" align="center" :width="operatorColumnWidth">
        <template #default="scope">
          <!--把表格右侧操作列的整个插槽-->
          <slot name="table_operator" v-bind:row="scope.row">
            <!--把表格右侧操作列的左侧插槽-->
            <slot name="table_operator_left" v-bind:row="scope.row"></slot>
            <el-button
              v-if="showEditButton && showEditButtonInTable && typeof baseUrl === 'string' && baseUrl.length"
              type="warning"
              size="small"
              icon="Edit"
              plain
              @click="editRow(scope.row)"
              >编辑</el-button
            >
            <el-popconfirm
              v-if="showDeleteButton && showDeleteButtonInTable && typeof baseUrl === 'string' && baseUrl.length"
              confirm-button-text="确定"
              cancel-button-text="取消"
              icon="InfoFilled"
              icon-color="red"
              title="确定要删除该记录吗？"
              @confirm="remove(scope.row)"
            >
              <template #reference>
                <el-button type="danger" size="small" icon="delete" plain>删除</el-button>
              </template>
            </el-popconfirm>
            <!--            <el-button  type="danger"  size="small" icon="delete" plain @click="remove(scope.row)">删除</el-button>-->
            <!--把表格右侧操作列的右侧插槽-->
            <slot name="table_operator_right" v-bind:row="scope.row"> </slot>
          </slot>
        </template>
      </el-table-column>
    </el-table>
    <!--分页插件-->
    <TablePagination v-if="pagination" v-bind="table" :changePageSize="changePageSize" :changePage="changePage" :layout="paginationLayout" />
  </div>
</template>

<script lang="ts" setup>
// 导入表格工具栏插件
import TableToolbar from '@/components/base/table/TableToolbar.vue';
// 导入分页插件
import TablePagination from '@/components/base/table/TablePagination.vue';
// 导入图片插件
import PictureComponent from '@/components/base/other/PictureComponent.vue';
import { ElMessage, ElMessageBox, ElTable } from 'element-plus';
import { ref, watch, type ModelRef } from 'vue';
// 导入项目接口
// 导入项目接口
import type { ResponseData, TableColumn, TableData } from '@/types/interface/base_interface';
// 导入字典
import { yesOrNoDict, dictToMap } from '@/api/dict';
import { noPicSrc } from '@/api/pic';

import Request from '@/api/request/request';
import { SemicolonPreference } from 'typescript';
//saveTableRow表示直接保存行数据
const emit = defineEmits(['selectionChange', 'rowClick', 'addRow', 'editRow', 'afterDeleteSuccess', 'saveRow']);
// 接收父组件传递过来的值
interface Props {
  //函数，用于对应表格组件的Hook。需要在父组件引入自定义的@/api/uem/useTableList.ts组件，然后将其中的部分属性传过来
  loadTableList: () => void; // 当每页数据显示数发生变化时触发的一个函数
  changePageSize: (page: number) => void; // 当每页数据显示数发生变化时触发的一个函数
  changePage: (page: number) => void; // 当页面发生变化时触发的一个函数
  query?: Record<string, any>; // 查询表单对象，初步设计是在导出表格时根据查询条件导出数据。
  //表格插件
  baseUrl: string; // 表格的请求接口地址。如果后端接口符合规则，可以通过相同的url接口地址，以不同的提交方式实现增删改查
  tableHeight?: string | number; // 表格的默认高度，同element ui table的height属性。默认为自动
  table: TableData; // 表格对象，包含表格数据和分页信息。表格数据实际业务并不需要，偷懒写法
  tableColumns: TableColumn[]; // 表格的列字段集合
  isTreeTable?: Boolean; // 是否树形表格，如果为树形表格，会增加扩展和折叠两个按钮，默认为不是树形表格
  isExpandAll?: boolean; //树形表格是否默认展开
  showToolBar?: Boolean; // 是否显示表格工具栏，默认显示
  showLeftToolBar?: Boolean; // 是否显示左侧的表格工具栏，默认显示
  showRightToolBar?: Boolean; // 是否显示右侧的表格工具栏，默认显示
  showEditButtonInToolBar?: Boolean; // 是否显示工具栏的编辑按钮，默认不显示
  showAddNewButton?: Boolean; // 在表格工具栏是否显示新增按钮
  showDeleteMultipleSelectionButton?: Boolean; // 在表格工具栏是否显示删除按钮,还要配合是否有删除地址和表格复选框按钮是否存在判断
  showOperatorColumn?: Boolean; // 是否显示表格右侧的操作栏，默认显示
  showDeleteButtonInTable?: Boolean; // 在表格的每行记录都增加删除按钮
  showEditButtonInTable?: Boolean; // 在表格的每行记录都增加编辑按钮
  showDeleteButton?: Boolean; // 是否显示删除按钮，如果不显示则整个表格插件都不显示
  showEditButton?: Boolean; //  是否显示编辑按钮，如果不显示则整个表格插件都不显示
  AddNewButtonText?: string; //新增按钮的文本
  downloadTemplateUrl?: string; // 下载模板地址，也决定表格工具栏是否显示下载模板按钮
  templateFileName?: string; // 下载模板的文件名
  downloadUrl?: string; // 下载表格地址，也决定表格工具栏是否显示下载表格按钮
  dataFileName?: string; // 下载数据的文件名
  importUrl?: string; // 导入地址，决定是否显示导入按钮
  importButtonText?: string; // 导入按钮的名称
  importExcelSuccessAndCloseDialog?: Boolean; // 上传成功是否自动关闭对话框
  showTableCheckbox?: Boolean; // 是否在表格左侧显示复选框按钮,也决定工具栏删除按钮是否显示
  showTableIndex?: Boolean; // 是否在表格左侧显示序号
  rowId?: string; // 表格行对象的主键属性，需要根据后端接口数据来决定。默认是id
  operatorColumnWidth?: number; // 表格右侧操作了大小
  allowEditTableCell?: Boolean; //是否允许表格可以双击单元格编辑
  //分页组件
  pagination?: Boolean; // 是否显示分页插件，默认显示
  paginationLayout?: string; // 分页布局，同element 组件
}
const props = withDefaults(defineProps<Props>(), {
  tableHeight: 500,
  query: () => ({}), // 返回空对象
  isTreeTable: () => Boolean(false),
  pagination: () => Boolean(true),
  showToolBarEditButton: () => Boolean(false),
  showDeleteMultipleSelectionButton: () => Boolean(true),
  showDeleteButtonInTable: () => Boolean(true),
  showEditButtonInTable: () => Boolean(true),
  showDeleteButton: () => Boolean(true),
  showEditButton: () => Boolean(true),
  showTableCheckbox: () => Boolean(true),
  showTableIndex: () => Boolean(false),
  showAddNewButton: () => Boolean(true),
  allowEditTableCell: () => Boolean(true),
  rowId: 'id',
  showToolBar: () => Boolean(true),
  showLeftToolBar: () => Boolean(true),
  showRightToolBar: () => Boolean(true),
  isExpandAll: () => Boolean(false),
  showOperatorColumn: () => Boolean(true),
  operatorColumnWidth: 180,
  importExcelSuccessAndCloseDialog: () => Boolean(true)
});
// watch(
//   () => props.deleteMultipleSelectionUrl,
//   (newVal: any, oldVal: any) => {
//     console.log(newVal, oldVal);
//   },
//   { immediate: true, deep: true }
// );

// 实现表格的刷新状态
const tableLoading = ref(false); // 表格加载状态
const changeTableLoading = (loading: boolean) => {
  tableLoading.value = loading;
};

// 实现表格的动态列显示
const tableColumnsVisible = ref<TableColumn[]>([]); // 定义用于显示的列
// 当列选择发生变化时，表格的显示数据也发生变化
const getColumnsSelected = (columnsSelected: string[]) => {
  tableColumnsVisible.value = [];
  props.tableColumns.forEach((tableColumn: TableColumn) => {
    if (columnsSelected.indexOf(tableColumn.prop) !== -1) {
      tableColumnsVisible.value.push(tableColumn);
    }
  });
};

// 表格复选框
// 复选框选择的记录row集合
const multipleSelection = defineModel<any[]>('multipleSelection', {
  required: false,
  default: []
});
// const multipleSelection = ref([]); // 复选框选择的记录row
const handleSelectionChange = (selection: any[]) => {
  // 当选择项发生变化时会触发该事件，这里用于获取选择的记录（多选）.value可以获取所有选择了的行记录row
  multipleSelection.value = selection;
  emit('selectionChange', multipleSelection.value);
};

// 单个记录的删除按钮操作
const remove = async (row: any): Promise<void> => {
  if (props.baseUrl) {
    const ids: any[] = [row[props.rowId]]; // 定义要批量删除的主键
    const deleteForm = {
      ids: ids.toString()
    };
    const resData = await new Request(props.baseUrl, null, { params: deleteForm }).delete();
    if (resData.code !== 406) {
      //如果没有强制删除异常
      if (resData.success) {
        //在删除成功后的回调
        emit('afterDeleteSuccess', multipleSelection.value);
        props.loadTableList(); // 刷新表格
      }
    } else {
      //如果弹出强制删除异常
      return focusDeleteMultipleSelection(deleteForm, resData.msg!);
    }
  }
};

// 点击添加按钮，由父组件来决定实现方法
const addRow = () => {
  emit('addRow', null);
};

// 树形表格扩展和收缩功能
// const isExpandAll = ref(true); // 是否全部展开
const refreshTable = ref(true); // 重新渲染表格的状态
// 定义表格ref对象
// const tableRef = ref();
// 定义表格的ref对象
const tableRef = ref<InstanceType<typeof ElTable>>();
// 定义函数，遍历树形表格所有节点，进行扩展或收缩。
const toggleAllRowExpansion = (array: any[], expand: boolean) => {
  // expand表示是否扩展
  // 递归算法在树形多的时候有些差，这里进行修改
  // array.forEach((row:any) => {
  //   tableRef.value.toggleRowExpansion(row, expand); // 全部折叠
  //   if (row.children && row.children.length > 0) {
  //     toggleAllRowExpansion(row.children, expand);
  //   }
  // });
  // 改进递归算法
  let childrens: any[] = []; // 获取本级所有子节点后再进行递归
  array.forEach((row: any) => {
    tableRef.value!.toggleRowExpansion(row, expand); // 全部折叠
    if (row.children && row.children.length > 0) {
      row.children.forEach((rowChildren: any) => {
        // 遍历子节点，主要要检查该子节点下是否还有节点，减少递归次数
        if (rowChildren.children && rowChildren.children.length > 0) {
          // 如果子节点下还有节点，则需要遍历该节点
          childrens.push(rowChildren);
        }
      });
    }
  });
  if (childrens.length > 0) {
    toggleAllRowExpansion(childrens, expand);
  }
};
// 点击扩展全部按钮
const expandAll = () => {
  toggleAllRowExpansion(props.table.data, true);
};
// 点击收缩全部按钮，用于树形表格
const shrinkAll = async () => {
  // 方法一：传统方法折叠。在节点多了之后，使用下述收缩速度会很慢，但并非性能原因，如果将浏览器变小只看到一两个菜单，收缩就还会很快。
  // 经过检查，速度慢的原因主要是表格行和列过多的原因导致。所以要控制列显示的数量
  toggleAllRowExpansion(props.table.data, false);
  // 方法二：下面是一个走捷径的把那法，让菜单默认是收缩的，通过v-if来重新渲染表格，达到快速收缩的效果。
  // refreshTable.value = false;
  // isExpandAll.value = false; // 让菜单默认折叠再重新渲染
  // await nextTick();
  // refreshTable.value = true;
};

// 表格的行点击事件
const rowClick = (row: any, column: number): void => {
  emit('rowClick', row);
};

// 编辑按钮操作
const editRow = (row: any): void => {
  emit('editRow', row);
};

// 多个删除操作
const deleteMultipleSelection = async (): Promise<void> => {
  if (multipleSelection.value.length > 0) {
    ElMessageBox.confirm(`确定要删除这${multipleSelection.value.length}个记录吗？`, '警告', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
      .then(async () => {
        const ids: any[] = []; // 定义要批量删除的主键
        for (let i = 0; i < multipleSelection.value.length; i += 1) {
          const item = multipleSelection.value[i];
          ids.push(item[props.rowId]);
        }
        const deleteForm = {
          ids: ids.toString()
        };
        if (props.baseUrl) {
          const resData: ResponseData = await new Request(props.baseUrl, null, { params: deleteForm }).delete();
          if (resData.code !== 406) {
            //如果没有强制删除异常
            if (resData.success) {
              //在删除成功后的回调
              emit('afterDeleteSuccess', multipleSelection.value);
              props.loadTableList(); // 刷新表格
            }
          } else {
            //如果弹出强制删除异常
            return focusDeleteMultipleSelection(deleteForm, resData.msg!);
          }
        }
      })
      .catch(() => {
        // 点击了取消按钮
      });
  } else {
    ElMessage.error('请至少选择一条数据');
  }
};
//强制删除
const focusDeleteMultipleSelection = (deleteForm: any, msg: string) => {
  return ElMessageBox.confirm(`${msg}。是否继续删除？删除后将无法恢复!`, '警告', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(async () => {
      const resData: ResponseData = await new Request(`${props.baseUrl}/force`, null, { params: deleteForm }).delete();
      //如果强制删除成功
      if (resData.success) {
        //在删除成功后的回调
        emit('afterDeleteSuccess', multipleSelection.value);
        props.loadTableList(); // 刷新表格
      }
    })
    .catch(() => {
      // 点击了取消按钮
    });
};

// 返回当前选中的行
const getSelectionRows = () => tableRef.value!.getSelectionRows();
//用于多选表格，切换某一行的选中状态， 如果使用了第二个参数，则可直接设置这一行选中与否
const toggleRowSelection = (row: any, selected: boolean) => tableRef.value!.toggleRowSelection(row, selected);
//用于单选表格，设定某一行为选中行， 如果调用时不加参数，则会取消目前高亮行的选中状态。
const setCurrentRow = (row: any) => tableRef.value!.setCurrentRow(row);
//清空表格选中的复选框
const clearSelection = () => tableRef.value!.clearSelection();
//重置表格编辑列，将其变为未编辑状态
const saveRow = (row: any) => {
  row._editColumnName = null;
  emit('saveRow', row);
};

defineExpose({
  // 参考vue3官方文档，需要将函数暴露出去才能被父组件调用，setup模式是不暴露的
  getSelectionRows,
  toggleRowSelection,
  setCurrentRow,
  clearSelection //清空表格
});
</script>
<style lang="scss" scoped></style>
